import {
  NOT_LOADED,
  LOAD_SOURCE_CODE,
  SKIP_BECAUSE_BROKEN,
  NOT_BOOTSTRAPPED,
  LOAD_ERROR
} from "../application/apps.helper";
import {
  smellLikeAPromise,
  flattenLifecycleArray,
  getProps
} from "./helper";
import {ensureTimeout} from "../application/timeouts";

export function toLoadPromise(app){
  if (app.status !== NOT_LOADED) {
    return Promise.resolve(app);
  }

  app.status = LOAD_SOURCE_CODE;

  /** ↓核心*/
  const loadPromise = app.loadFunction(getProps(app));

  if(!smellLikeAPromise(loadPromise)){
    app.status = SKIP_BECAUSE_BROKEN;
    return Promise.reject(new Error(`loadPromise must return a promise or thenable object`))
  }

  return loadPromise.then(appConfig/*←远程返回的app配置信息*/ => {
    if (typeof appConfig !== 'object') {
      throw new Error('');
    }

    const errors = [];
    // 必须要包含如下↓三个生命周期 否则报错
    ['bootstrap', 'mount', 'unmount'].forEach(lifecycle => {
      if (!appConfig[lifecycle]) {
        errors.push(`lifecycle:${lifecycle} must be exists`);
      }
    });

    if (errors.length) {
      app.status = SKIP_BECAUSE_BROKEN;
      console.error(errors);
      return app;
    }

    app.status = NOT_BOOTSTRAPPED;
    // 一个app生命周期可能包含多个返回promise的fn
    // appConfig.bootstrap = [p1fn,p2fn,p3fn,...]
    // flattenLifecycleArray是将p1fn、p2fn、p3fn...串联起来(一个执行完,返回的promise成功了,再执行下一个)
    app.bootstrap = flattenLifecycleArray(appConfig.bootstrap, `app: ${app.name} bootstrapping`);
    app.mount = flattenLifecycleArray(appConfig.mount, `app: ${app.name} mounting`);
    app.unmount = flattenLifecycleArray(appConfig.unmount, `app: ${app.name} unmounting`);
    app.timeouts = ensureTimeout(appConfig.timeouts);

    return app;
  })
  .catch(e => {
    app.status = LOAD_ERROR;
    console.error(e);
  });
}
